#include "../Headers/tLogger.hpp"

#include <fstream>
#include <iostream>
#include <sstream>
//#include <iostream>
#include <iomanip>
#include <codecvt>
#include <map>
#include <Windows.h>

#include <mutex>

using namespace std;

std::wstring TLogger::filenameTXT;
bool TLogger::flagFilenameSet = false;
size_t TLogger::writtenSizeCount = 0;
int TLogger::breakFileIndex = -1;
volatile bool TLogger::flagBreakingFile = false;
std::wstring TLogger::breakingBuffer;
CheckIfShouldWriteCB TLogger::checkShouldWrite;
bool TLogger::flagHold = false;
bool TLogger::flagNextNewLine = false;
bool TLogger::flagAlsoPrint = false;
string TLogger::holdBuffer = "";
string TLogger::indentStr = "";
wstring TLogger::indentWStr = L"";
std::vector<std::string> TLogger::warningNames;
std::vector<int> TLogger::warningCounts;

size_t TLogger::lastWriteOffsetStart;
std::string TLogger::lastWriteStr;

std::mutex globalLoggerMutex;

class TFormaterForTLogger {
public:
	static string formatCurrentDateTimeToString() {
		time_t     now = time(0);
		char       buf[128];
		struct tm now_time;
		localtime_s(&now_time, &now);

		// Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
		// for more information about date/time format
		strftime(buf, sizeof(buf), "%Y_%m_%d_%H_%M_%S", &now_time);
		return string(buf);
	}

	static std::wstring string2wstring(std::string strIn) {
		// this part not working with c++17
		//try
		//{
		//	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
		//	return converter.from_bytes(strIn);
		//}
		//catch (std::range_error& e)
		//{
		size_t length = strIn.length();
		std::wstring result;
		result.reserve(length);
		for (size_t i = 0; i < length; i++)
		{
			result.push_back(strIn[i] & 0xFF);
		}
		return result;
		//}
	}

	static std::wstring int2str(int val, int digit) {
		wstring s;
		wstringstream ss(s);
		if (digit <= 0) {
			ss << val;
		}
		else {
			ss << std::setfill(L'0') << std::setw(digit) << val;
		}
		return ss.str();
	}
};

void CreateDirectoryForFileRecursive_logger(const std::wstring& path) {
	std::wstring::size_type pos = path.find_first_of(L"\\/", 0);
	std::wstring currentPath;

	while ((pos = path.find_first_of(L"\\/", pos + 1)) != std::wstring::npos) {
		currentPath = path.substr(0, pos);
		if (!CreateDirectory(currentPath.c_str(), NULL)) {
			if (GetLastError() != ERROR_ALREADY_EXISTS) {
				std::wcerr << L"Failed to create directory: " << currentPath << std::endl;
				return;
			}
		}
	}

	// Create the final directory
	//if (!CreateDirectory(path.c_str(), NULL)) {
	//	if (GetLastError() != ERROR_ALREADY_EXISTS) {
	//		std::wcerr << L"Failed to create directory: " << path << std::endl;
	//	}
	//}
}

// file may be replaced. see  TLogger::writeMain
static wofstream globalFile;

TLogger::TLogger() {
	TLogger::addIndent();
}

TLogger::TLogger(std::string newContent, bool withTime, bool flagWriteVanillaIn) {
	if (newContent.length() > 0) {
		flagWithTime = withTime;
		flagWriteVanilla = flagWriteVanillaIn;
		localLoggerName = newContent;

		//if (flagWriteVanilla) {
		//	TLogger::writeVanilla(localLoggerName);
		//}
		//else {
		TLogger::writeLineX(localLoggerName + " start", false, flagWithTime);
		//}
		TLogger::addIndent();
	}
}

TLogger::~TLogger() {
	if (localLoggerName.length() > 0) {
		TLogger::dropIndent();
		//if (flagWriteVanilla) {
		//	TLogger::writeVanilla(localLoggerName);
		//	TLogger::writeLine(localLoggerName + " complete");
		//	TLogger::writeLineX(newContent + " start", false, withTime);
		//}
		//else {
		//}
		TLogger::writeLineX(localLoggerName + " complete", false, flagWithTime);
	}
}

void TLogger::init() {
}

void TLogger::clearWarningCount() {
	warningNames.clear();
	warningCounts.clear();
}

void TLogger::setFile(std::string filenameIn, bool flagErase, bool forceSingleFile) {
	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
	wstring fileW = converter.from_bytes(filenameIn);
	setFile(fileW, flagErase, forceSingleFile);
}

void TLogger::setFile(std::wstring filenameIn, bool flagErase, bool forceSingleFile) {
	filenameTXT = filenameIn;
	if (filenameTXT.size() <= 1)
		return;
	CreateDirectoryForFileRecursive_logger(filenameTXT);
	ofstream myfile;
	if (flagErase)
		myfile.open(filenameTXT, ios::out);
	else
		myfile.open(filenameTXT, ios::out | ios::app);
	myfile.close();
	flagFilenameSet = true;
	writeLine("New log file");
	writeLine(TFormaterForTLogger::formatCurrentDateTimeToString());
	if (!forceSingleFile) {
		writeLine("Will auto split file after growing too large");
		breakFileIndex = 0;
	}
	else {
		breakFileIndex = -1;
	}
}

void TLogger::setFile(char* filenameIn, bool flagErase, bool forceSingleFile) {
	if (filenameIn == nullptr)
		return;
	setFile(std::string(filenameIn), flagErase, forceSingleFile);
}

void TLogger::setFlagAlsoPrint() {
	flagAlsoPrint = true;
	writeLine("Set logger to print");
}

void TLogger::setNoNewLine() {
	flagNextNewLine = false;
}

void TLogger::write(std::string newContent,
	bool flagSkip,
	bool flagWithTime,
	int addSpaceToMeetThisLength) {
	if (flagSkip) {
		return;
	}

	// add space to meet length, if needed
	concatPadding(newContent, addSpaceToMeetThisLength);

	if (flagWithTime) {
		concatTime(newContent);
	}

	// add indent for new lines
	if (flagNextNewLine) {
		concatIndent(newContent);
	}

	flagNextNewLine = true;
	writeMain(newContent + "\n");


	//#ifdef BLOCK_WRITING_LOG
	//	return;
	//#endif
	//	if (flagSkip) {
	//		return;
	//	}
	//
	//	// add space to meet length, if needed
	//	concatPadding(newContent, addSpaceToMeetThisLength);
	//
	//	if (flagWithTime) {
	//		concatTime(newContent);
	//	}
	//
	//	// add indent for new lines
	//	if (flagNextNewLine) {
	//		concatIndent(newContent);
	//	}
	//
	//	writeMain(newContent);
	//
	//	flagNextNewLine = false;
}

void TLogger::writeVanilla(std::string newContent) {
	writeMain(newContent);
	if (newContent.back() != '\n') {
		setNoNewLine();
	}
}

void TLogger::writeVanilla(std::wstring newContent) {
	writeMain(newContent);
	if (newContent.back() != L'\n') {
		setNoNewLine();
	}
}

void TLogger::writeLine(std::string newContent) {
	writeLineX(newContent,
		false,
		false,
		-1);
}

void TLogger::write(std::wstring newContent,
	bool flagSkip,
	bool flagWithTime,
	int addSpaceToMeetThisLength) {
	// add space to meet length, if needed
	concatPadding(newContent, addSpaceToMeetThisLength);

	if (flagWithTime) {
		concatTime(newContent);
	}

	// add indent for new lines
	if (flagNextNewLine) {
		concatIndent(newContent);
	}

	setNoNewLine();
	writeMain(newContent);;
}

void TLogger::writeLine(std::wstring newContent) {
	writeLineX(newContent,
		false,
		false,
		-1);
}

void TLogger::writeLineP(const wchar_t* newContent) {
	writeLine(newContent);
}

bool TLogger::writeLineX(std::string newContent,
	bool flagSkip,
	bool flagWithTime,
	int addSpaceToMeetThisLength,
	bool withAutoIndent) {
	if (flagSkip) {
		return false;
	}

	// add space to meet length, if needed
	concatPadding(newContent, addSpaceToMeetThisLength);

	if (flagWithTime) {
		concatTime(newContent);
	}

	// add indent for new lines
	if (flagNextNewLine && withAutoIndent) {
		concatIndent(newContent);
	}

	flagNextNewLine = true;
	return writeMain(newContent + "\n");
}

bool TLogger::writeLineX(std::wstring newContent,
	bool flagSkip,
	bool flagWithTime,
	int addSpaceToMeetThisLength,
	bool withAutoIndent) {
	if (flagSkip) {
		return false;
	}

	// add space to meet length, if needed
	concatPadding(newContent, addSpaceToMeetThisLength);

	if (flagWithTime) {
		concatTime(newContent);
	}

	// add indent for new lines
	if (flagNextNewLine && withAutoIndent) {
		concatIndent(newContent);
	}

	flagNextNewLine = true;
	return writeMain(newContent + L"\n");
}

void TLogger::writeWarnning(std::string newContent, bool withTime) {
	string contentOut = makeWarnning(newContent, withTime);
	if (!writeLineX(contentOut, false, withTime)) {
#ifdef _CONSOLE
		cout << contentOut << endl;
#endif
	}
}

void TLogger::writeWarnning(std::wstring newContent, bool withTime) {
	wstring contentOut = makeWarnning(newContent, withTime);
	if (!writeLineX(contentOut, false, withTime)) {
#ifdef _CONSOLE
		wcout << contentOut << endl;
#endif
	}
}

void TLogger::writeWarnningP(const wchar_t* newContent) {
	writeWarnning(newContent, true);
}

bool TLogger::writeFirstNWarnings(std::string warningContent, std::string warningName, int printWarningCount, bool withTime) {
	for (int idx = 0; idx < warningNames.size(); idx++) {
		if (warningNames[idx].compare(warningName) == 0) {
			if (warningCounts[idx] >= printWarningCount) {
				return false;
			}
			else {
				writeWarnning(warningContent, withTime);
				warningCounts[idx]++;
				return true;
			}
		}
	}
	writeWarnning(warningContent, withTime);
	warningNames.push_back(warningName);
	warningCounts.push_back(1);
	return true;
}

void TLogger::addIndent(int indentSpace) {
	indentStr.append("-| ");
}

void TLogger::dropIndent() {
	if (indentStr.size() >= 3) {
		indentStr.resize(indentStr.size() - 3);
	}
}

void TLogger::clearIndents() {
	indentStr.resize(0);
}

void TLogger::hold(bool quietly) {
	if (!quietly) {
		writeLine("Holding logger");
	}
	flagHold = true;
	holdBuffer.reserve(1024 * 1024);
}

void TLogger::clear() {
	flagHold = false;
	holdBuffer = "";
}

void TLogger::flush(bool quietly) {
	flagHold = false;
	writeMain(holdBuffer);
	holdBuffer = "";
	if (!quietly) {
		writeLine("Logger flushed");
	}
}

//void TLogger::removeFrom(size_t start) {
//	globalFile.seekp(start, std::ios_base::beg);
//	auto pos = getOffset();
//	int stop = 1;
//}

std::wstring TLogger::getFilename() {
	return filenameTXT;
}

std::string TLogger::makeWarnning(std::string newContent, bool withTime) {
	string contentOut;
	const int MIN_LENGTH = 13;
	int lengthSpaces = 0;
	int length = (int)newContent.size() + 4;
	if (length < MIN_LENGTH) {
		lengthSpaces = (MIN_LENGTH + 1 - length) / 2;
		length += lengthSpaces * 2;
	}
	int lengthDashBefore = (length - 7) / 2 - 1;
	int lengthDashAfter = length - 9 - lengthDashBefore;
	for (int idx = 0; idx < lengthDashBefore; idx++)
		contentOut += '-';
	contentOut += " WARNING ";
	for (int idx = 0; idx < lengthDashAfter; idx++)
		contentOut += '-';
	contentOut += "\n| ";
	for (int idx = 0; idx < lengthSpaces; idx++)
		contentOut += ' ';
	contentOut += newContent;
	for (int idx = 0; idx < lengthSpaces; idx++)
		contentOut += ' ';
	contentOut += " |\n";
	for (int idx = 0; idx < length; idx++)
		contentOut += '-';
	contentOut += '\n';
	return contentOut;
}

std::wstring TLogger::makeWarnning(std::wstring newContent, bool withTime) {
	wstring contentOut;
	const int MIN_LENGTH = 13;
	int lengthSpaces = 0;
	int length = (int)newContent.size() + 4;
	if (length < MIN_LENGTH) {
		lengthSpaces = (MIN_LENGTH + 1 - length) / 2;
		length += lengthSpaces * 2;
	}
	int lengthDashBefore = (length - 7) / 2 - 1;
	int lengthDashAfter = length - 9 - lengthDashBefore;
	for (int idx = 0; idx < lengthDashBefore; idx++)
		contentOut += '-';
	contentOut += L" WARNING ";
	for (int idx = 0; idx < lengthDashAfter; idx++)
		contentOut += '-';
	contentOut += L"\n| ";
	for (int idx = 0; idx < lengthSpaces; idx++)
		contentOut += ' ';
	contentOut += newContent;
	for (int idx = 0; idx < lengthSpaces; idx++)
		contentOut += ' ';
	contentOut += L" |\n";
	for (int idx = 0; idx < length; idx++)
		contentOut += '-';
	contentOut += '\n';
	return contentOut;
}

size_t TLogger::setWriteCallback(CheckIfShouldWriteCB callbackIn) {
	checkShouldWrite = callbackIn;
	return getOffset();
}

size_t TLogger::getOffset() {
	if (globalFile.is_open()) {
		return globalFile.tellp();
	}
	else {
		return 0;
	}
}

bool TLogger::writeNoProc(std::wstring newContent, bool flush) {
	if (flagFilenameSet) {
		const std::locale utf8_locale = std::locale(std::locale(), new std::codecvt_utf8<wchar_t>());
		if (!globalFile.is_open()) {
			globalFile.open(filenameTXT, ios::out | ios::app);
			globalFile.imbue(utf8_locale);
		}
		auto pos0 = getOffset();
		globalFile.write(&(newContent[0]), newContent.size());
		globalFile.flush();
		auto pos1 = getOffset();
		if (flush) {
			globalFile.flush();
		}
	}
	return true;
}

std::wstring makeErrorHint(std::wstring hint, std::wstring objectName) {
	return hint + L" @" + objectName;
}

void TLogger::formatSourceCodeLineAndTimeIfNonZero(std::wstring hint, std::wstring objectName,
	std::wstring& errorHintOut,
	long* time, std::wstring& errorLintOut,
	const std::source_location& location) {
	if (*time == 0) {
		*time = clock();

		// source file name __FILE__ 
		// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
		// source code line
		// https://en.cppreference.com/w/cpp/utility/source_location/line
		errorHintOut = makeErrorHint(hint, objectName);
		string s;
		stringstream ss(s);
		ss << "<";
		ss << location.file_name();
		ss << ">: \"";
		ss << location.function_name();
		ss << "\" L:";
		ss << location.line();
		string lineStr = ss.str();

		errorLintOut = TFormaterForTLogger::string2wstring(lineStr);
	}
}

void TLogger::removeError(std::wstring hint, std::wstring objectName,
	std::wstring& errorHintOut,
	long* time, std::wstring& errorLineOut) {
	if (*time > 0) {
		wstring thisHint = makeErrorHint(hint, objectName);
		if (errorHintOut.compare(thisHint) == 0) {
			*time = 0;
			errorHintOut = L"";
			errorLineOut = L"";
		}
	}
}

void TLogger::concatPadding(std::string& str, int addSpaceToMeetThisLength) {
	int diff = addSpaceToMeetThisLength - str.length();
	for (int count = 0; count < diff; count++) {
		str.push_back(' ');
	}
}

void TLogger::concatPadding(std::wstring& str, int addSpaceToMeetThisLength) {
	int diff = addSpaceToMeetThisLength - str.length();
	for (int count = 0; count < diff; count++) {
		str.push_back(' ');
	}
}

void TLogger::concatTime(std::string& str) {
	// 3600*24*1000=86,400,000 8 digit good for a day
#define LOG_TIME_DIGIT 8
	int timeMS = clock();

	std::ostringstream oss;
	// 
	oss << std::setfill('0') << std::setw(LOG_TIME_DIGIT) << timeMS;
	string header = oss.str() + " ";

	str = header + str;
}

void TLogger::concatTime(std::wstring& str) {
	int timeMS = clock();

	std::wostringstream oss;
	oss << std::setfill(L'0') << std::setw(9) << timeMS;
	wstring header = oss.str() + L" ";

	str = header + str;
}

void TLogger::concatIndent(std::string& str) {
	str = indentStr + str;
}

void TLogger::concatIndent(std::wstring& str) {
	str = indentWStr + str;
}

bool TLogger::writeMain(std::string content) {
	wstring contentW = TFormaterForTLogger::string2wstring(content);
	return writeMain(contentW);
}

bool TLogger::writeMain(std::wstring content) {
	scoped_lock lock(globalLoggerMutex);
	if (flagHold) {
		//holdBuffer.append(content);
		return false;
	}
	else {
		if (flagFilenameSet) {
			if (checkShouldWrite != NULL) {
				if (!checkShouldWrite(content)) {
					return false;
				}
			}

			return writeCore(content);
		}
		else {
			wcout << content;
			wcout.flush();
			return true;
		}
	}
}

bool TLogger::writeCore(std::wstring content) {
	const static std::locale utf8_locale(std::locale("C"), new std::codecvt_utf8<wchar_t>);
	if (flagBreakingFile) {
		breakingBuffer.append(content);
	}
	else {
#ifdef PLATFORM_SERVER
		if (!globalFile.is_open()) {
			globalFile.open(filenameTXT, ios::out | ios::app);
			globalFile.imbue(utf8_locale);
		}
		globalFile.write(&(content[0]), content.size());
		globalFile.flush();
#endif

		if (breakFileIndex >= 0) {
			writtenSizeCount += content.size();
			if ((fileBreakSizeLimit > 0) && (writtenSizeCount >= fileBreakSizeLimit)) {
				// break file
				flagBreakingFile = true;
				globalFile.close();

				wstring oldName = filenameTXT;
				wstring format = oldName.substr(oldName.find_last_of(L"."));
				wstring newName = filenameTXT + L".part_" + TFormaterForTLogger::int2str(breakFileIndex, 6) + format;

				_wrename(oldName.c_str(), newName.c_str());
				globalFile.open(filenameTXT, ios::out);
				flagBreakingFile = false;

				writtenSizeCount = 0;
				globalFile.write(&(breakingBuffer[0]), breakingBuffer.size());
				breakingBuffer.clear();
				globalFile.flush();

				breakFileIndex++;
			}
		}
	}

	if (flagAlsoPrint) {
		wcout << content;
		wcout.flush();
		return true;
	}
	else {
		return false;
	}
}

TClassLogger::TClassLogger(std::string classHintIn, bool withTime) {
	classHint = classHintIn;
}

TClassLogger::~TClassLogger() {

}

void TClassLogger::write(std::string newContent,
	bool flagSkip,
	bool flagWithTime,
	int addSpaceToMeetThisLength) {
	TLogger::write(classHint + newContent, flagSkip, flagWithTime, addSpaceToMeetThisLength);
}

void TClassLogger::writeLine(std::string content,
	bool flagSkip,
	bool flagWithTime,
	int addSpaceToMeetThisLength) {
	TLogger::writeLineX(classHint + content, flagSkip, flagWithTime, addSpaceToMeetThisLength);
}

void TClassLogger::writeWarning(std::string content) {
	TLogger::writeWarnning(content);
}


TPercentageUpdater::~TPercentageUpdater() {
	//SLogger::writeLine("~TPercentageUpdater");
//#ifndef _CONSOLE
//	return;
//#endif
#ifdef FLAG_DISPLAY_CORE_FEEDBACK
	if (released)
		return;
	if (!ignore) {
		update(totalIterationNum);
		cout << "   " << flush;
	}
#endif
}

TPercentageUpdater::TPercentageUpdater(int totalIterationNumIn, int updateNumIn, std::string progressNameIn) {
	//#ifndef _CONSOLE
	//	return;
	//#endif
	totalIterationNum = totalIterationNumIn;
	if (totalIterationNumIn < 0) {
		ignore = true;
		return;
	}
	totalIterationNum = totalIterationNumIn;
	updateNum = updateNumIn;
	updateInterval = max(totalIterationNum / updateNum, 1);
	progressName = progressNameIn;
	ignore = false;
	progressContentBeforePercentage = "Constructing " + progressNameIn + " [";
	progressContentAfterPercentage = "] " + progressBar;
#ifdef FLAG_DISPLAY_CORE_FEEDBACK
	cout << "Constructing " << progressName << " ... " << flush;
#endif
}

void TPercentageUpdater::update(int iterationIdx) {
	//#ifndef _CONSOLE
	//	return;
	//#endif
	if (ignore) {
		//cout << "" << flush;
		return;
	}
	int newPercentage = (int)floor(float(iterationIdx) / totalIterationNum * 100);
	if (newPercentage > currentPercentage) {
		currentPercentage = newPercentage;
		cout << '\r' << flush;
		cout << progressContentBeforePercentage;
		if (currentPercentage < 10) {
			cout << "  " << currentPercentage;
		}
		else if (currentPercentage < 100) {
			int digitTen = currentPercentage / 10;
			cout << " " << digitTen << currentPercentage - digitTen * 10;
		}
		else {
			cout << "100";
		}
		cout << "%";
		int currentDisplayLen = progressBarOffset + currentPercentage / 2;
		cout << progressContentAfterPercentage.substr(0, currentDisplayLen);
		if (currentDisplayLen < progressContentAfterPercentage.length())
			for (int idx = 0; idx < progressContentAfterPercentage.length() - currentDisplayLen; idx++)
				cout << " ";
		cout << "]" << flush;
	}
}

void TPercentageUpdater::completeNow() {
	//#ifndef _CONSOLE
	//	return;
	//#endif
	released = true;
	if (ignore)
		return;
	update(totalIterationNum + 1);
	cout << endl;
}

std::vector<int> TGlobalErrorRecorder::errorFlags;
std::vector<char*> TGlobalErrorRecorder::errorHints;

void TGlobalErrorRecorder::addError(int errorFlag, const char* errorHint) {
	errorFlags.push_back(errorFlag);
	string errorHintPtr = errorHint;
	char* errorHintCp = new char[errorHintPtr.length()];
	memcpy(errorHintCp, errorHint, errorHintPtr.length() + 1);
	errorHints.push_back(errorHintCp);
}

bool TGlobalErrorRecorder::anyErrorRaised(const char* errorCheckPos) {
	if (errorFlags.size() > 0) {
		TLogger::writeLine("Error before" + string(errorCheckPos));
		return true;
	}
	return false;
}

struct RpBlkShared {
	static int activeBlockCount;
	static int repeatingCount;
	static map<string, TLoggerRepeatBlock::BlockData> repBlocks;
};
int RpBlkShared::activeBlockCount = 0;
int RpBlkShared::repeatingCount = 0;
map<string, TLoggerRepeatBlock::BlockData> RpBlkShared::repBlocks;

TLoggerRepeatBlock::TLoggerRepeatBlock(std::string codeIn) {
	code = codeIn;

	// initialize entry
	auto& data = RpBlkShared::repBlocks[code];
	data.flagActive = true;
	data.newRepData.clear();
	data.newRepData.reserve(data.lastRepData.length());
	data.flagMatchedSoFar = true;

	TLogger::setWriteCallback(checkShouldWrite);
	RpBlkShared::activeBlockCount++;
}

TLoggerRepeatBlock::~TLoggerRepeatBlock() {
	RpBlkShared::activeBlockCount--;
	if (RpBlkShared::activeBlockCount == 0) {
		//TLogger::setWriteCallback(NULL);
	}
	auto& data = RpBlkShared::repBlocks[code];
	data.lastRepData = data.newRepData;
	if (data.flagMatchedSoFar) {
		if (!data.flagRepeating) {
			TLogger::writeNoProc(L"Rep begin {", false);
			RpBlkShared::repeatingCount++;
		}
		TLogger::writeNoProc(TFormaterForTLogger::int2str(data.count, -1), false);
		data.count = (data.count + 1) % 10;
		data.flagRepeating = true;
	}
	else {
		if (data.flagRepeating) {
			data.flagRepeating = false;
			RpBlkShared::repeatingCount--;
		}
	}
}

bool TLoggerRepeatBlock::checkShouldWrite(std::wstring& log) {
	if (RpBlkShared::activeBlockCount > 0) {
		for (auto& block : RpBlkShared::repBlocks) {
			auto& data = block.second;
			// only one active is processed for now
			if (data.flagActive) {
				if (!data.flagMatchedSoFar) {
					data.newRepData.append(log);
					return true;
				}
				else {
					// keep checking
					if (data.newRepData.length() + log.length() > data.lastRepData.length()) {
						// longer, not matching
						data.flagMatchedSoFar = false;
					}
					else {
						size_t offsetDiff = data.newRepData.length();
						for (size_t offset = 0; offset < log.length(); offset++) {
							if (log[offset] != data.lastRepData[offset + offsetDiff]) {
								data.flagMatchedSoFar = false;
								break;
							}
						}
					}
					data.newRepData.append(log);
					if (!data.flagMatchedSoFar) {
						log = data.newRepData;
						if (data.flagRepeating) {
							TLogger::writeNoProc(L"} end\n", false);
							data.count = 0;
						}
						return true;
					}
					return false;
				}
			}
		}
		// should never reach this. 
		return false;
	}
	if (RpBlkShared::repeatingCount > 0) {
		for (auto& block : RpBlkShared::repBlocks) {
			auto& data = block.second;
			// only one active is processed for now
			if (data.flagRepeating) {
				TLogger::writeNoProc(L"} end\n", false);
				data.count = 0;

				data.flagMatchedSoFar = false;
				data.flagRepeating = false;
				RpBlkShared::repeatingCount--;
			}
		}
	}
	return true;
}